Skip to content

fix: decode only the viewed bytes of Uint8Array log data#772

Merged
taeold merged 1 commit into
GoogleCloudPlatform:mainfrom
dylayed:fix/logger-uint8array-pooled-buffer
Jun 24, 2026
Merged

fix: decode only the viewed bytes of Uint8Array log data#772
taeold merged 1 commit into
GoogleCloudPlatform:mainfrom
dylayed:fix/logger-uint8array-pooled-buffer

Conversation

@dylayed

@dylayed dylayed commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

When execution-id logging is enabled, the framework intercepts process.stdout/process.stderr writes and re-decodes the data to attach execution context (src/logger.ts). The Uint8Array branch decoded data.buffer:

decodedData = Buffer.from(data.buffer).toString();

data.buffer is the entire backing ArrayBuffer and ignores the view's byteOffset / byteLength. Node.js allocates most Buffers from a shared internal pool, so a Buffer written to stdout is frequently a view with a non-zero byteOffset into a much larger ArrayBuffer. As a result, decoding data.buffer captures unrelated pool bytes surrounding the real message and produces corrupted log output.

Reproduction

const pool = Buffer.allocUnsafe(64);
const a = pool.subarray(8, 8 + 11);
a.write('hello world');

Buffer.from(a.buffer).toString();
// => 8192-byte string of pool garbage with "hello world" buried in the middle

Buffer.from(a.buffer, a.byteOffset, a.byteLength).toString();
// => "hello world"

In practice this means a user function that does process.stdout.write(Buffer.from('...')) (or logs via any library that emits Buffers) gets garbled logs whenever execution-id support is on.

Fix

Decode only the bytes the view spans:

decodedData = Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString();

Why the existing test didn't catch it

The uint8array test uses new Uint8Array(Buffer.from(sampleText)), which copies into a fresh, exactly-sized ArrayBuffer with byteOffset === 0 and byteLength === buffer.byteLength — the one case where reading data.buffer happens to be correct.

Testing

  • Added a regression test that logs through a pooled, non-zero-offset view. It fails before the fix and passes after.
  • Full suite green: 107 passing.

🤖 Generated with Claude Code

@google-cla

google-cla Bot commented Jun 23, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

When execution-id logging is enabled, stdout/stderr writes are
intercepted and re-decoded to attach execution context. The Uint8Array
branch decoded `data.buffer`, which is the entire backing ArrayBuffer
and ignores the view's `byteOffset`/`byteLength`.

Node.js allocates most Buffers from a shared internal pool, so a Buffer
written to stdout is frequently a view with a non-zero byteOffset into a
much larger ArrayBuffer. Decoding `data.buffer` therefore captured
unrelated pool bytes surrounding the real message, producing corrupted
log output (e.g. logging the whole 8 KiB pool instead of "hello world").

Decode `Buffer.from(data.buffer, data.byteOffset, data.byteLength)` so
only the bytes the view spans are read. Added a regression test that
logs through a pooled, non-zero-offset view.
@dylayed dylayed force-pushed the fix/logger-uint8array-pooled-buffer branch from 616878f to 2b52ffd Compare June 24, 2026 00:15
@taeold

taeold commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Huh interesting. Thanks for the contribution!

@taeold taeold merged commit 8b780fc into GoogleCloudPlatform:main Jun 24, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants